
#region Imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using Annunciator = PHSRAG.WebControls.Annunciator;
using CommonSearchContext = PHSRAG.Insight21.SearchContext.CommonSearchContext;
using DataAccess = PHSRAG.Utility.DataAccess;
using OrgTree = PHSRAG.Insight21.InsightWebControls.OrgTree;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
using UserContext = PHSRAG.Insight21.Context.UserContext;
using Policy = PHSRAG.Insight21.Policy;
#endregion

namespace PHSRAG.Insight21.Common.SearchSupport
{
	/// <summary>
	/// </summary>
	public partial class COSPicker : System.Web.UI.UserControl
	{
		#region Constants
		private const string ClientScriptKey = "clientScript_9B7C7615-EA17-4268-B777-B7694F1F5A58";
		private const string OrganizationListKey = "organizationList_9B7C7615-EA17-4268-B777-B7694F1F5A58";
		private const string PickerType = "COS";
        private const string JavascriptWindowTitle = "SetWindowTitle";
		#endregion

		#region Instance Variables
		private Policy.ICachePolicy	cachePolicy;
		#endregion

		#region Event Handlers
		/// <summary>
		/// Handler for the close-button.
		/// </summary>
		/// <param name="sender">Button which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		protected void OnCloseWindow(object sender, System.EventArgs e)
		{
			// Update the current search criteria using the search context.
			// It is CRUCIAL that the updated search criteria be stored back in the search context; failing which
			// later invocation to interrogate the criteria through the search context will NOT show the PI selection.
			// It would be easier to compare the selection based on each key/value pair. The chiefCode-orgName combination
			// is the key, and the orgID is the value. The selections are therefore converted into Hashtables for futher
			// compariesion.

			CommonSearchContext searchContext = (CommonSearchContext)cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
			SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());

			string currentSelection = orgTree.Selection;
			System.Diagnostics.Trace.WriteLine(currentSelection);
			Hashtable currentSelectionMap = ConvertSelectionStringToHashtable(currentSelection);
	
			string oldSelection = searchCriteria[PickerType] as string;
			Hashtable oldSelectionMap = (oldSelection == null) ? null : ConvertSelectionStringToHashtable(oldSelection);

			if (currentSelection.Length > 0 && ((oldSelection == null) || !IsSameSelection(oldSelectionMap, currentSelectionMap)))
			{
				searchContext.SetPickerSearchCriteria(PickerType,currentSelection);
			}

			// Generate client-side script to close the window within which this control is loaded. In addition, a
			// is made to a javascript functino on the opener page to display the choice made.

			if (!Page.ClientScript.IsClientScriptBlockRegistered(ClientScriptKey))
			{
				int count = currentSelectionMap.Keys.Count;
				string cosMessage = currentSelection;
				if (count == 1)
				{
					Pair nameID = SplitSelection(currentSelection);
					if (nameID != null)
						cosMessage = (string)nameID.First;
				}
				else
					cosMessage = string.Format("{0} selected", count);

				string script = string.Format(
					"<script language=\"javascript\">\n" +
					"window.opener.SetPickerSelection(\"{0}\", \"{1}\");\n" +
					"window.close();\n" +
					"</script>\n", PickerType, cosMessage);

				Page.ClientScript.RegisterClientScriptBlock(GetType( ), ClientScriptKey, script);
			}
		}
		/// <summary>
		/// Handles for the control load event.
		/// </summary>
		/// <param name="sender">The entity which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		/// <remarks>
		/// Load the tree with organization information on non-postback.
		/// </remarks>
		protected void OnPageLoad(object sender, System.EventArgs e)
		{
			if (!IsPostBack)
				LoadOrgTree();
		}

		/// <summary>
		/// Reset the selection state. This is done by removing the picker value from the search criteria.
		/// The window is closed at the end.
		/// </summary>
		/// <param name="sender">Control which raised the event</param>
		/// <param name="e">Argument associated with the event</param>
		protected void OnReset(object sender, System.EventArgs e)
		{
			CommonSearchContext searchContext = (CommonSearchContext)cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
			SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());

			string currentSelection = searchCriteria[PickerType];
			if (currentSelection != null)
			{
				searchContext.ClearPickerSearchCriteria(PickerType);
			}

			if (!Page.ClientScript.IsClientScriptBlockRegistered(ClientScriptKey))
			{
				const string script = "<script language=\"javascript\">\nwindow.close();\n</script>\n";
				Page.ClientScript.RegisterClientScriptBlock(GetType( ), ClientScriptKey, script);
			}
		}
		#endregion

        #region Overrides
        /// <summary>
        /// Register clientside scripts.
        /// </summary>
        /// <param name="e">Argument associated with the event.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (!Page.ClientScript.IsClientScriptBlockRegistered(JavascriptWindowTitle))
            {
                string script2 =
                    "<script language=\"javascript\">\n" +
                    "\twindow.pageTitle.text = \"Organization Search\";\n" +
                    "</script>\n";

                Page.ClientScript.RegisterClientScriptBlock(GetType( ), JavascriptWindowTitle, script2);
            }
        }
        #endregion

		#region Private Methods
		/// <summary>
		/// Convert the selection string (which may contain multiple COS selections) into a Hashtable. The key in the
		/// Hashtable is the org-ID and the value is of the form "chiefCode-name".
		/// </summary>
		/// <param name="selection">String of all '|' seaprated COS selections</param>
		/// <returns>Hashtable of sections</returns>
		private Hashtable ConvertSelectionStringToHashtable(string selection)
		{
			Hashtable hashtable = new Hashtable();
			string[] keyValueList = selection.Split('|');
			foreach (string keyValue in keyValueList)
			{
				Pair nameID = SplitSelection(keyValue);
				if (nameID != null)
					hashtable[nameID.Second] = nameID.First;
			}
			return hashtable;
		}

		/// <summary>
		/// Compare two Hashtable representation of COS selections and determine if their contents are the same.
		/// </summary>
		/// <param name="h1">First selection</param>
		/// <param name="h2">Second selection</param>
		/// <returns>True if the two selections are the same; false otherwise</returns>
		private bool IsSameSelection(Hashtable h1, Hashtable h2)
		{
			if (h1.Count != h2.Count)
				return false;

			foreach (string key in h1.Keys)
			{
				if (!h2.ContainsKey(key))
					return false;
				if (h1[key] != h2[key])
					return false;
			}
			return true;
		}

		/// <summary>
		/// Get the organization information for the current user and bind that information to the org tree.
		/// If there is no orgranization to display, warn the user.
		/// </summary>
		private void LoadOrgTree()
		{
			CommonSearchContext searchContext = (CommonSearchContext)cachePolicy.GetCachedObject(CommonSearchContext.CacheKey);
			SearchCriteria searchCriteria = searchContext.GetSearchCriteria(Page.Request.Url.ToString());
			string selection = searchCriteria[PickerType] as string;
			if (selection != null)
				orgTree.CurrentSelection = ConvertSelectionStringToHashtable(selection);

			DataTable pickerDataTable = searchContext.GetPickerDataForOrgTree(PickerType, "GetOrganizationList");
			if (pickerDataTable.Rows.Count == 0)
			{
				annunciator.Title = "Data Load Warning:";
				annunciator.Message = string.Format("No {0} data found matching the search criteria.", PickerType);
				annunciator.Visible = true;
			}
			else
			{
				DataTable orgInfo = cachePolicy.GetCachedObject(OrganizationListKey) as DataTable;
				if (orgInfo == null)
				{
					orgInfo = DataAccess.GetDataTable(DataAccess.ConnectionString, "GetOrganizationList");
					cachePolicy.Cache(OrganizationListKey, orgInfo);
				}

				orgTree.DataSource = new DataTable[]{pickerDataTable, orgInfo};

//				annunciator.Title = "Note:";
//				annunciator.Message = "Select organization(s) and click the \"Close Window\" button to add to your search criteria.";
//				annunciator.Visible = true;
			}
		}

		/// <summary>
		/// Split the specified selection into a pair of values. The selection is of the form "name:id".
		/// </summary>
		/// <param name="selection">Selection string to split</param>
		/// <returns>Pair containing the name and ID</returns>
		private Pair SplitSelection(string selection)
		{
			Regex regex = new Regex(@"(?<name>[^:]+):(?<id>\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
			Match match = regex.Match(selection);
			if (match.Success)
				return new Pair(match.Groups["name"].Value, match.Groups["id"].Value);
			return null;
		}
		#endregion

		#region Web Form Designer generated code
		/// <summary>
		/// Handler for the page initialize event.
		/// </summary>
		/// <param name="e">Argument associated with the event</param>
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);

			cachePolicy = (Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey];
		}
		
		/// <summary>
		///		Required method for Designer support - do not modify
		///		the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.Load += new System.EventHandler(this.OnPageLoad);

		}
		#endregion
	}
}

// --- EOF ---
